﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml.Serialization;

using Idlesoft.Utils;

namespace Idlesoft.Cli
{
	/// <summary>
	/// Inherits from XmlElementAttribute used for xml serialization; implements ICliAttribute used in CliBuilder operations.
	/// </summary>
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
	public class CliElementAttribute : XmlElementAttribute, ICliAttribute
	{
		#region ctors

		/// <summary>
		/// Ctor that allows the user to specify the flags to be used rather than be auto-generated.
		/// </summary>
		/// <param name="flags">Specific flags to be used.</param>
		public CliElementAttribute(params string[] flags)
		{
			Flags = flags;
			FlagTypes = FlagTypes.Undef;
		}
		#endregion ctors

		#region props
		/// <summary>
		/// Internal property used to arg matches including the name and the values.
		/// </summary>
		public object[] Args 
		{ 
			get { return _CliAttribute.Args; } 
			set { _CliAttribute.Args = value; } 
		}

		/// <summary>
		/// Boolean property to determine if the cliattribute is an Option as opposed to a BuiltIn or Required.
		/// </summary>
		public bool Option { get { return _CliAttribute.Option; } }

		/// <summary>
		/// Boolean property to determin if the cliattribute is decorating the CliBuilder class instead of a user-defined one.
		/// </summary>
		public bool BuiltIn { get { return _CliAttribute.BuiltIn; } }

		/// <summary>
		/// Optional boolean property to mark a cliattribute as required.  This will cause an error to happen and the usage to print if it is not set during CliBuilder.Create.
		/// </summary>
		public bool Required
		{
			get { return _CliAttribute.Required; }
			set { _CliAttribute.Required = value; }
		}

		/// <summary>
		/// Optional property to override the default flag types as defined during the call to CliBuilder.Create or its default value.  This governs how and how many of the flags are auto-generated.
		/// </summary>
		public FlagTypes FlagTypes
		{
			get { return _CliAttribute.FlagTypes; }
			set { _CliAttribute.FlagTypes = value; }
		}

		/// <summary>
		/// Internal property that determines what kind of values are appropriate for the ICliAttribute decorated field or property.
		/// </summary>
		public ValueTypes ValueTypes { get { return _CliAttribute.ValueTypes; } }

		/// <summary>
		/// Optional property to override the name of the property.  This overridden Name is then used when auto-generating the flags to match against.
		/// </summary>
		public string Name
		{
			get { return _CliAttribute.Name; }
			set { _CliAttribute.Name = value; }
		}

		/// <summary>
		/// Optional property used when the help usage prints to the console on bad input are when invoked.
		/// </summary>
		public string Description
		{
			get { return _CliAttribute.Description; }
			set { _CliAttribute.Description = value; }
		}

		/// <summary>
		/// Optional string array of flags to be used to match against.  This turns off the auto-generated flags irrespectives of the FlagTypes etc.
		/// </summary>
		public string[] Flags
		{
			get { return _CliAttribute.Flags; }
			set { _CliAttribute.Flags = value; }
		}

		/// <summary>
		/// Internal property used to store the values once they have been parsed out of the command line args.  Do not attempt to set this property.
		/// </summary>
		public object[] Values
		{
			get { return _CliAttribute.Values; }
			set { _CliAttribute.Values = value; }
		}

		/// <summary>
		/// Optional property to supply default values to be used when no values are found during parsing.  Note that this will not be used for cliattributes marked as Required.
		/// </summary>
		public object Default
		{
			get { return _CliAttribute.Default; }
			set { _CliAttribute.Default = value; }
		}

		/// <summary>
		/// Internal property to store the MemberInfo loaded during the CliBuilder.Create execution.  Do not attempt to set this property.
		/// </summary>
		public MemberInfo MemberInfo
		{
			get { return _CliAttribute.MemberInfo; }
			set { _CliAttribute.MemberInfo = value; }
		}

		/// <summary>
		/// Internal property to get the type of the property|field that the MemberInfo property points to.  Will throw an exception if MemberInfo is not set.
		/// </summary>
		public Type MemberInfoType { get { return _CliAttribute.MemberInfoType; } }
		#endregion props

		#region methods

		/// <summary>
		/// Internal method to determin if a cliattribute has been assigned.  Checks against the default values; this will probably be improved to be more accurate.
		/// </summary>
		/// <param name="target">The target object that the MethodInfo property is point to.</param>
		/// <returns></returns>
		public bool IsAssigned(object target) { return _CliAttribute.IsAssigned(target); }

		/// <summary>
		/// Internal method to determin if either the Name or any of the Values match the given arg.
		/// </summary>
		/// <param name="arg"></param>
		/// <returns></returns>
		public bool MatchesArg(string arg) { return _CliAttribute.MatchesArg(arg); }

		public override string ToString() { return _CliAttribute.ToString(); }

		public override bool Equals(object obj) { return _CliAttribute.Equals(obj); }

		public override int GetHashCode() { return _CliAttribute.GetHashCode(); }
		#endregion methods

		#region fields
		private ICliAttribute _CliAttribute = new CliAttribute();
		#endregion fields
	}
}
